////////////////////////////////////////////////////////////////////////////
//  File:           pba.cpp
//  Author:         Changchang Wu
//  Description :   implementation of ParallelBA, which is a wrapper around
//                  the GPU-based and CPU-based implementations
//
//  Copyright (c) 2011  Changchang Wu (ccwu@cs.washington.edu)
//    and the University of Washington at Seattle 
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU General Public
//  License as published by the Free Software Foundation; either
//  Version 3 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  General Public License for more details.
//
////////////////////////////////////////////////////////////////////////////////
#include <stdlib.h>
#include <new>
#include "pba.h"
#include "SparseBundleCU.h"
#include "SparseBundleCPU.h"

ParallelBA::ParallelBA(DeviceT device)
{
    //The wrapper intends to provide different implementations.

    if(device >= PBA_CUDA_DEVICE_DEFAULT)  
#ifndef PBA_NO_GPU
	{
		SparseBundleCU * cuba = new SparseBundleCU(device - PBA_CUDA_DEVICE0);
		if(cuba->GetMemCapacity() > 0)
		{
			_optimizer = cuba;
		}else
		{
			device = PBA_CPU_FLOAT;
			_optimizer = NewSparseBundleCPU(false);
			delete cuba;
		}
	}else 
#else
        device = PBA_CPU_FLOAT; 
#endif
    if(device == PBA_CPU_FLOAT)              _optimizer = NewSparseBundleCPU(false);
    else if(device == PBA_CPU_DOUBLE)        _optimizer = NewSparseBundleCPU(true);
    else                                     _optimizer = NULL;
}

ParallelBA::~ParallelBA()
{
    if(_optimizer) delete _optimizer;

}

void ParallelBA::ParseParam(int narg, char** argv)
{
    _optimizer->ParseParam(narg, argv);
}

ConfigBA*  ParallelBA::GetInternalConfig()
{
    if(_optimizer)    return _optimizer->GetInternalConfig();
    else            return NULL; 
}

void ParallelBA:: SetFixedIntrinsics(bool fixed)
{
    _optimizer->SetFixedIntrinsics(fixed); 
}
void ParallelBA:: EnableRadialDistortion(DistortionT enabled)
{
    _optimizer->EnableRadialDistortion(enabled); 
}
void ParallelBA:: SetNextTimeBudget(int seconds)
{
    _optimizer->SetNextTimeBudget(seconds); 
}

void ParallelBA::SetNextBundleMode(BundleModeT mode)
{
	_optimizer->SetNextBundleMode(mode);
}

void ParallelBA::SetCameraData(size_t ncam,  CameraT* cams)
{
    _optimizer->SetCameraData(ncam, cams);
}

void ParallelBA::SetPointData(size_t npoint, Point3D* pts)
{
    _optimizer->SetPointData(npoint, pts);
}


void ParallelBA::SetProjection(size_t nproj, const Point2D* imgpts, const int* point_idx, const int* cam_idx)
{
    _optimizer->SetProjection(nproj, imgpts, point_idx, cam_idx);

}
int  ParallelBA::RunBundleAdjustment()
{
    return _optimizer->RunBundleAdjustment();
}

float ParallelBA::GetMeanSquaredError()
{
    return _optimizer->GetMeanSquaredError();
}

int ParallelBA::GetCurrentIteration()
{
    return _optimizer->GetCurrentIteration();
}
void ParallelBA::AbortBundleAdjustment()
{
    return _optimizer->AbortBundleAdjustment();
}

void ParallelBA::ReserveStorage(size_t ncam, size_t npt, size_t nproj)
{
    if(_optimizer) _optimizer->ReserveStorage(ncam, npt, nproj);
}

void ParallelBA::SetFocalMask(const int* fmask, float weight)
{
	if(_optimizer && weight > 0) _optimizer->SetFocalMask(fmask, weight);
}


void* ParallelBA::operator new (size_t  size)
{
  void * p = malloc(size);
  if (p == 0)  
  {
      const std::bad_alloc ba;
      throw ba; 
  }
  return p; 
}


ParallelBA * NewParallelBA(ParallelBA::DeviceT device)
{
    return new ParallelBA(device); 
}

int	ParallelBA_GetVersion()
{
	return 105;
}

